import { ANONYMOUS_DECORATOR_KEY, jwtConstants } from '@app/common/constants';
import { Account } from '@app/common/types/account.type';
import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlExecutionContext } from '@nestjs/graphql';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGraphqlGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private reflector: Reflector,
  ) {}
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    try {
      const isAllowAnoymous = this.reflector.getAllAndOverride<boolean>(
        ANONYMOUS_DECORATOR_KEY,
        [context.getHandler(), context.getClass()],
      );
      if (isAllowAnoymous) {
        return true;
      }
      const request = GqlExecutionContext.create(context).getContext().req;
      const token = this.extractIdentityFromHeader<Account>(request);
      if (token) {
        request.user = token;
        return true;
      }
    } catch (error) {
      throw new UnauthorizedException();
    }
  }

  private extractIdentityFromHeader<T extends object>(
    request: Request,
  ): T | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    if (type != 'Bearer') {
      return undefined;
    }
    const payload = this.jwtService.verify<T>(token, {
      secret: jwtConstants.secret,
    });

    return payload;
  }
}
